/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Haystack Software Inc. All rights reserved.
 *  Licensed under the PolyForm Strict License 1.0.0. See License.txt in the project root for
 *  license information.
 *--------------------------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See code-license.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { TextAreaWrapper } from "vs/editor/browser/controller/textAreaInput"
import { DisposableStore, toDisposable } from "vs/base/common/lifecycle"
import {
  IRecorded,
  IRecordedCompositionEvent,
  IRecordedEvent,
  IRecordedInputEvent,
  IRecordedKeyboardEvent,
  IRecordedTextareaState,
} from "vs/editor/test/browser/controller/imeRecordedTypes"
import * as browser from "vs/base/browser/browser"
import * as platform from "vs/base/common/platform"
import { mainWindow } from "vs/base/browser/window"
;(() => {
  const startButton = <HTMLButtonElement>(
    mainWindow.document.getElementById("startRecording")!
  )
  const endButton = <HTMLButtonElement>(
    mainWindow.document.getElementById("endRecording")!
  )

  let inputarea: HTMLTextAreaElement
  const disposables = new DisposableStore()
  let originTimeStamp = 0
  let recorded: IRecorded = {
    env: null!,
    initial: null!,
    events: [],
    final: null!,
  }

  const readTextareaState = (): IRecordedTextareaState => {
    return {
      selectionDirection: inputarea.selectionDirection,
      selectionEnd: inputarea.selectionEnd,
      selectionStart: inputarea.selectionStart,
      value: inputarea.value,
    }
  }

  startButton.onclick = () => {
    disposables.clear()
    startTest()
    originTimeStamp = 0
    recorded = {
      env: {
        OS: platform.OS,
        browser: {
          isAndroid: browser.isAndroid,
          isFirefox: browser.isFirefox,
          isChrome: browser.isChrome,
          isSafari: browser.isSafari,
        },
      },
      initial: readTextareaState(),
      events: [],
      final: null!,
    }
  }
  endButton.onclick = () => {
    recorded.final = readTextareaState()
    console.log(printRecordedData())
  }

  function printRecordedData() {
    const lines = []
    lines.push(`const recorded: IRecorded = {`)
    lines.push(`\tenv: ${JSON.stringify(recorded.env)}, `)
    lines.push(`\tinitial: ${printState(recorded.initial)}, `)
    lines.push(
      `\tevents: [\n\t\t${recorded.events.map((ev) => printEvent(ev)).join(",\n\t\t")}\n\t],`,
    )
    lines.push(`\tfinal: ${printState(recorded.final)},`)
    lines.push(`}`)

    return lines.join("\n")

    function printString(str: string) {
      return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'")
    }
    function printState(state: IRecordedTextareaState) {
      return `{ value: '${printString(state.value)}', selectionStart: ${state.selectionStart}, selectionEnd: ${state.selectionEnd}, selectionDirection: '${state.selectionDirection}' }`
    }
    function printEvent(ev: IRecordedEvent) {
      if (
        ev.type === "keydown" ||
        ev.type === "keypress" ||
        ev.type === "keyup"
      ) {
        return `{ timeStamp: ${ev.timeStamp.toFixed(2)}, state: ${printState(ev.state)}, type: '${ev.type}', altKey: ${ev.altKey}, charCode: ${ev.charCode}, code: '${ev.code}', ctrlKey: ${ev.ctrlKey}, isComposing: ${ev.isComposing}, key: '${ev.key}', keyCode: ${ev.keyCode}, location: ${ev.location}, metaKey: ${ev.metaKey}, repeat: ${ev.repeat}, shiftKey: ${ev.shiftKey} }`
      }
      if (
        ev.type === "compositionstart" ||
        ev.type === "compositionupdate" ||
        ev.type === "compositionend"
      ) {
        return `{ timeStamp: ${ev.timeStamp.toFixed(2)}, state: ${printState(ev.state)}, type: '${ev.type}', data: '${printString(ev.data)}' }`
      }
      if (ev.type === "beforeinput" || ev.type === "input") {
        return `{ timeStamp: ${ev.timeStamp.toFixed(2)}, state: ${printState(ev.state)}, type: '${ev.type}', data: ${ev.data === null ? "null" : `'${printString(ev.data)}'`}, inputType: '${ev.inputType}', isComposing: ${ev.isComposing} }`
      }
      return JSON.stringify(ev)
    }
  }

  function startTest() {
    inputarea = document.createElement("textarea")
    mainWindow.document.body.appendChild(inputarea)
    inputarea.focus()
    disposables.add(
      toDisposable(() => {
        inputarea.remove()
      }),
    )
    const wrapper = disposables.add(new TextAreaWrapper(inputarea))

    wrapper.setValue("", `aaaa`)
    wrapper.setSelectionRange("", 2, 2)

    const recordEvent = (e: IRecordedEvent) => {
      recorded.events.push(e)
    }

    const recordKeyboardEvent = (e: KeyboardEvent): void => {
      if (e.type !== "keydown" && e.type !== "keypress" && e.type !== "keyup") {
        throw new Error(`Not supported!`)
      }
      if (originTimeStamp === 0) {
        originTimeStamp = e.timeStamp
      }
      const ev: IRecordedKeyboardEvent = {
        timeStamp: e.timeStamp - originTimeStamp,
        state: readTextareaState(),
        type: e.type,
        altKey: e.altKey,
        charCode: e.charCode,
        code: e.code,
        ctrlKey: e.ctrlKey,
        isComposing: e.isComposing,
        key: e.key,
        keyCode: e.keyCode,
        location: e.location,
        metaKey: e.metaKey,
        repeat: e.repeat,
        shiftKey: e.shiftKey,
      }
      recordEvent(ev)
    }

    const recordCompositionEvent = (e: CompositionEvent): void => {
      if (
        e.type !== "compositionstart" &&
        e.type !== "compositionupdate" &&
        e.type !== "compositionend"
      ) {
        throw new Error(`Not supported!`)
      }
      if (originTimeStamp === 0) {
        originTimeStamp = e.timeStamp
      }
      const ev: IRecordedCompositionEvent = {
        timeStamp: e.timeStamp - originTimeStamp,
        state: readTextareaState(),
        type: e.type,
        data: e.data,
      }
      recordEvent(ev)
    }

    const recordInputEvent = (e: InputEvent): void => {
      if (e.type !== "beforeinput" && e.type !== "input") {
        throw new Error(`Not supported!`)
      }
      if (originTimeStamp === 0) {
        originTimeStamp = e.timeStamp
      }
      const ev: IRecordedInputEvent = {
        timeStamp: e.timeStamp - originTimeStamp,
        state: readTextareaState(),
        type: e.type,
        data: e.data,
        inputType: e.inputType,
        isComposing: e.isComposing,
      }
      recordEvent(ev)
    }

    wrapper.onKeyDown(recordKeyboardEvent)
    wrapper.onKeyPress(recordKeyboardEvent)
    wrapper.onKeyUp(recordKeyboardEvent)
    wrapper.onCompositionStart(recordCompositionEvent)
    wrapper.onCompositionUpdate(recordCompositionEvent)
    wrapper.onCompositionEnd(recordCompositionEvent)
    wrapper.onBeforeInput(recordInputEvent)
    wrapper.onInput(recordInputEvent)
  }
})()
